package com.example.base.job;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Classname JobConfig
 * @Description TODO
 * @Date 2023/9/25 11:15
 * @Created by XiongXiong
 * @Author: X.I.O
 */
@Slf4j
@Configuration
public class JobConfig implements ApplicationContextAware {

    private Map<String,Object> classObject;

    private ApplicationContext applicationContext ;

    public Map<String,Object> getClassObject(){
        return this.classObject;
    }


    public Object getJobObjectByClassName(String className){
        if(classObject==null){
            return null;
        }
        Collection<Object> objects=classObject.values();
        for (Object object : objects) {
            if(object.getClass().getName().equals(className)){
                return object;
            }
        }
        return null;
    }

    public Object getJobObjectByAnnotationName(String annotationName){
        if(classObject==null){
            return null;
        }
        return classObject.get(annotationName);
    }

    @PostConstruct
    public void setUp() {
        // 根据注解获取bean ,key is bean name ,value is bean object
        Map<String, Object> map = this.applicationContext.getBeansWithAnnotation(Job.class);
        this.classObject=map;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext=applicationContext;
    }

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Bean
    @Order(2)
    public SchedulerFactoryBean getSchedulerFactoryBean() throws IOException {
        if(threadPoolTaskExecutor == null){
            threadPoolTaskExecutor=getThreadPoolTaskExecutor();
            log.error("threadPoolTaskExecutor is null");
            // System.exit(0);
        }
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        // propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
        //在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        //创建SchedulerFactoryBean
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setTaskExecutor(threadPoolTaskExecutor);
        // factory.setQuartzProperties(propertiesFactoryBean.getObject());
        //这样当spring关闭时，会等待所有已经启动的quartz job结束后spring才能完全shutdown。
        factory.setWaitForJobsToCompleteOnShutdown(true);
        factory.setOverwriteExistingJobs(false);
        factory.setStartupDelay(1);


        return factory;
    }

    @Bean("taskExecutor")
    @Primary
    @Order(1)
    public ThreadPoolTaskExecutor getThreadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setMaxPoolSize(5);
        threadPoolTaskExecutor.setCorePoolSize(2);
        RejectedExecutionHandler handler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                log.error("线程池超过最大容量,进行扩容 {} ",executor.getPoolSize());
                executor.setMaximumPoolSize(10);
                Thread thread = new Thread(r);
                thread.start();
                log.error(r.toString());
            }
        };
        threadPoolTaskExecutor.setRejectedExecutionHandler(handler);
        return threadPoolTaskExecutor;
    }
}
